import os
from collections import namedtuple
import hashlib

import pytest
import asyncio

from ..file_download.file_download import FileDownload
from ..file_download.parsing import Parser


def test_check_tree_element_is_directory() -> None:
    """ Тестируем проверку на то, является ли элемент дерева директорией """

    file_tree = Parser().parse_file_tree()

    for element in file_tree:
        if type(file_tree[element]) == dict:
            result = FileDownload().check_tree_element_is_directory(file_tree, element)
            assert result == True


def test_get_path_to_uploaded_files() -> None:
    """ Тестируем получение пути к загруженным файлам """

    path_to_uploaded_files = os.path.abspath(
        os.path.join(
            os.path.dirname( __name__ ),
            'uploaded_files'
        )
    )
    result = FileDownload().get_path_to_uploaded_files()

    assert path_to_uploaded_files == result


def test_create_directories_for_file_tree() -> None:
    """ Тестируем создание директорий для дерева файлов """

    file_tree = Parser().parse_file_tree()
    created_elements = file_tree.keys()
    FileDownload().create_directories_for_file_tree(file_tree)

    path_to_downloaded_files = FileDownload().get_path_to_uploaded_files()
    list_of_available_files = os.listdir(path_to_downloaded_files)

    for created_element in created_elements:
        file_path = f'{path_to_downloaded_files}/{created_element}'
        element_is_directory = os.path.isdir(file_path)
        directory_exists = created_element in list_of_available_files
        if element_is_directory and not directory_exists: assert False


@pytest.mark.asyncio
async def test_download_file() -> None:
    """ Тестируем загрузку файла """

    file_tree = list(Parser().parse_file_tree().items())
    file_name, file_url = [element for element in file_tree if type(element[1]) == str][0]
    path_to_downloaded_files = FileDownload().get_path_to_uploaded_files()
    file_path = f'{path_to_downloaded_files}/{file_name}'

    await FileDownload().download_file(file_url, file_path)

    if not os.path.exists(path_to_downloaded_files): assert False


def test_get_list_of_downloaded_file_path() -> None:
    """ Тестируем получение списка путей файлов указанной директории """

    list_of_downloaded_file_paths = []
    path_to_downloaded_files = FileDownload().get_path_to_uploaded_files()
    FileDownload().get_list_of_downloaded_file_path(
        list_of_downloaded_file_paths,
        path_to_downloaded_files
    )

    for file_path in list_of_downloaded_file_paths:
        element_exists = os.path.exists(file_path)
        if not element_exists: assert element_exists


def test_get_sha256_hash_of_file() -> None:
    """ Тестируем получение sha256 хэша файла """

    current_file_path = __file__
    current_file_hash = ''

    with open(current_file_path, 'rb') as file:
        bytes = file.read()
        hash = hashlib.sha256(bytes).hexdigest();
        current_file_hash = hash

    result = FileDownload().get_sha256_hash_of_file(current_file_path)

    assert current_file_hash == result


def test_get_list_of_sha256_file_hashes() -> None:
    """ Тестируем получение списка sha256 хешей переданных файлов """

    list_of_sha256_file_hashes = []
    list_of_downloaded_file_paths = []
    FilePathHash = namedtuple('FilePathHash', ['file_path', 'hash'])

    FileDownload().get_list_of_downloaded_file_path(
        list_of_downloaded_file_paths,
        FileDownload().get_path_to_uploaded_files()
    )

    for file_path in list_of_downloaded_file_paths:
        hash = FileDownload().get_sha256_hash_of_file(file_path)
        file_path_hash = FilePathHash(file_path, hash)
        list_of_sha256_file_hashes.append(file_path_hash)

    result = FileDownload().get_list_of_sha256_file_hashes(
        list_of_downloaded_file_paths
    )

    assert list_of_sha256_file_hashes == result


def test_get_list_of_sha256_hashes_of_uploaded_files() -> None:
    """ Тестируем получение списка sha256 хэшей загржуженных файлов """

    list_of_downloaded_file_paths = []
    FileDownload().get_list_of_downloaded_file_path(
        list_of_downloaded_file_paths,
        FileDownload().get_path_to_uploaded_files()
    )

    list_of_sha256_file_hashes = FileDownload().get_list_of_sha256_file_hashes(
        list_of_downloaded_file_paths
    )

    list_of_sha256_hashes_of_uploaded_files = FileDownload().get_list_of_sha256_hashes_of_uploaded_files()

    assert list_of_sha256_hashes_of_uploaded_files == list_of_sha256_file_hashes


@pytest.mark.asyncio
async def test_get_list_of_tasks_for_downloading_files() -> None:
    """ Тестируем получение списка задач для загрузки файлов """

    task_list_of_downloading_files = []
    file_tree = Parser().parse_file_tree()

    await FileDownload().get_list_of_tasks_for_downloading_files(
        file_tree,
        task_list_of_downloading_files
    )

    for task in task_list_of_downloading_files:
        assert isinstance(task, asyncio.Task)
        task.cancel()
